package com.example.zsr.downloadcontinue.download;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.example.zsr.downloadcontinue.ToolUtils.ContantsUtils;
import com.example.zsr.downloadcontinue.ToolUtils.SharePreferencesUtils;
import com.example.zsr.downloadcontinue.db.DBThreadListener;
import com.example.zsr.downloadcontinue.db.DBThreadListenerImp;
import com.example.zsr.downloadcontinue.entity.FileInfo;
import com.example.zsr.downloadcontinue.entity.ThreadInfo;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by zhengshaorui on 2017/2/22.
 */

public class DownloadTask {
    private static final String TAG = "DownloadTask";
    private Context mContext;
    private long downloadlength = 0;
    private FileInfo mFileInfo;
    public  boolean isPause = false;

    public  ExecutorService mExecutor ;
    private static final int FILE_ERROR = 2;

    Handler mDeliver = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == FILE_ERROR){
                String error_msg = (String) msg.obj;
                /*if (error_msg.contains("SocketTimeoutException")) {
                    Toast.makeText(mContext, fileinfo.getFileName() + " 连接超时，正在重试", Toast.LENGTH_SHORT).show();
                    //启动多个线程
                    for (ThreadInfo info : threads) {
                        DownloadThread downloadThread = new DownloadThread(info);
                        // downloadThread.start();
                        sExecutorService.execute(downloadThread);


                        mThreadList.add(downloadThread);
                    }
                }*/

            }
        }
    };





    private List<DownloadThread> mThreadList ;

    private DBThreadListener mDbThreadListener;
    public DownloadTask(Context mContext,int threadcount) {
        this.mContext = mContext;
        mDbThreadListener = new DBThreadListenerImp(mContext);
        mExecutor = Executors.newFixedThreadPool(threadcount);
    }
    List<ThreadInfo> threads;

    public void download(FileInfo fileInfo,DownloadCallback callback){
        mFileInfo = fileInfo;
        threads = mDbThreadListener.getThreads(fileInfo.getApkurl());
        if(fileInfo.getBtnstatus() == ContantsUtils.START){
            isPause = false;
        }else{
            isPause = true;
        }

        if (threads.size() == 0){
            //由于是多线程，所以，我们在这里应该重新对 threadinfo 处理

            //分成很多小块来下载,用线程数的平方，假如有5个线程，则一个文件分成25块来下载
            int count = mFileInfo.getThreadCount() * mFileInfo.getThreadCount();

            int threadLength = mFileInfo.getLength() / count; //每个线程的大小
            String url = mFileInfo.getApkurl();

            for (int i = 0; i < count; i++) {
                ThreadInfo threadInfo = new ThreadInfo(i,url,
                        i*threadLength,(i+1)*threadLength-1,0,0);

                if (i == count - 1){ //最后一个除不尽，则end用文件长度来实现
                    threadInfo.setEnd(mFileInfo.getLength());
                }

                threads.add(threadInfo); //把创建的集合添加到 list 里面
                //开始之前先检测是否数据库有线程信息
                mDbThreadListener.insertThread(threadInfo); //第一次的时候，把线程保存到数据库
            }
        }

        //由于是多个线程，我们需要一个list管理起来
        mThreadList = new ArrayList<DownloadThread>();

        //启动多个线程
        for (ThreadInfo info : threads) {
            DownloadThread downloadThread = new DownloadThread(info,callback);
            mExecutor.execute(downloadThread);

            mThreadList.add(downloadThread);
        }
    }


    private synchronized  void checkThreadFinished(DownloadCallback callback){
        boolean allfinished = true;
        for(DownloadThread downloadThread : mThreadList){
            if (!downloadThread.isFinished){
                allfinished = false;
            }
        }
        callback.downloadStatus(mFileInfo.getApkurl(),ContantsUtils.FILE_LOADING);
        if (allfinished){
            callback.success(mFileInfo);
            Intent intent = new Intent(ContantsUtils.FILE_FINISHED);
            intent.putExtra("fileinfo",mFileInfo);
            mContext.sendBroadcast(intent);

            SharePreferencesUtils.saveInteanData(ContantsUtils.FILE_PROGRESS,
                    mFileInfo.getApkurl(),100);
            SharePreferencesUtils.saveFloatData(ContantsUtils.FLOAT_FILEDOWNLOAD,
                    mFileInfo.getApkurl(),(float)mFileInfo.getLength()/1024/1024);
            SharePreferencesUtils.saveFloatData(ContantsUtils.FLOAT_FILESIZE,
                    mFileInfo.getApkurl(),(float)mFileInfo.getLength()/1024/1024);

            callback.downloadStatus(mFileInfo.getApkurl(),ContantsUtils.FILE_COMPLETED);

        }
    }

    class DownloadThread extends Thread{
        ThreadInfo mThreadInfo;
        public boolean isFinished = false;
        DownloadCallback mCallback;
        public DownloadThread(ThreadInfo threadinfo,DownloadCallback callback) {
            this.mThreadInfo = threadinfo;
            this.mCallback = callback;
           // Log.d(TAG, "DownloadThread: "+threadinfo);
        }


        @Override
        public void run() {
            super.run();
            HttpURLConnection conn = null;
            RandomAccessFile raf = null;
            BufferedInputStream bis = null;

            try {

            //    Log.d(TAG, "run: "+mThreadInfo);
                URL url = new URL(mThreadInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                //加上这句是为了防止connection.getContentLength()获取不到
                conn.setRequestProperty("Accept-Encoding", "identity");
                conn.setRequestMethod("GET");
                conn.setReadTimeout(20000);
                conn.setConnectTimeout(20000);


                //设置下载位置
                int start = mThreadInfo.getStart()+mThreadInfo.getFinished(); //起始位置
                int end = mThreadInfo.getEnd(); //结束位置
                conn.setRequestProperty("Range", "bytes="+start+"-"+end);
                //保存整个文件的大小
                downloadlength += mThreadInfo.getFinished();


                //文件写入位置
                File file = new File(mFileInfo.getDir(),mFileInfo.getFileName());
                raf = new RandomAccessFile(file,"rwd");
                raf.seek(start);

                int len = -1;
                byte[] bytes = new byte[1024*4];
                bis = new BufferedInputStream(conn.getInputStream());
                long time = System.currentTimeMillis();
                long lastDownloadlength = downloadlength;  //保存上一次的大小
                Intent progresslIntent = new Intent(ContantsUtils.UPDATE_PROGRESS);

                while( (len = bis.read(bytes)) != -1 ){
                    raf.write(bytes,0,len);
                    downloadlength += len; //
                    //保存每个线程的大小
                    mThreadInfo.setFinished(mThreadInfo.getFinished() + len);
                    if (isPause) {
                        //数据库保存每段线程的断点位置
                        mDbThreadListener.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(),
                                mThreadInfo.getFinished());
                        mCallback.downloadStatus(mFileInfo.getApkurl(),ContantsUtils.FILE_PAUSE);
                        return;
                    }
                    if (System.currentTimeMillis() - time > 500){
                        float speed = (float)(downloadlength - lastDownloadlength)/
                                (System.currentTimeMillis() - time);
                        time = System.currentTimeMillis();
                        mFileInfo.setSpeed(speed); //保存下载的平均速度
                        int progress = (int) (downloadlength*100/mFileInfo.getLength());

                        float downloadsize = (float)downloadlength/1024/1024;
                        float filesize = (float)mFileInfo.getLength()/1024/1024;
                        mFileInfo.setProgress(progress);
                        mFileInfo.setFiledown(downloadsize);
                        mFileInfo.setFilesize(filesize);
                        progresslIntent.putExtra(ContantsUtils.FILEINFO,mFileInfo);
                        mContext.sendBroadcast(progresslIntent);

                        SharePreferencesUtils.saveInteanData(ContantsUtils.FILE_PROGRESS,
                                mFileInfo.getApkurl(),progress);
                        SharePreferencesUtils.saveFloatData(ContantsUtils.FLOAT_FILEDOWNLOAD,
                                mFileInfo.getApkurl(),downloadsize);
                        SharePreferencesUtils.saveFloatData(ContantsUtils.FLOAT_FILESIZE,
                                mFileInfo.getApkurl(),filesize);

                    Log.d(TAG, "progress: "+mFileInfo.getFileName()+" "+(downloadlength*100/mFileInfo.getLength()));
                    }

                    //以百分比的形式传递
                }
                if(downloadlength == mFileInfo.getLength()){
                    mFileInfo.setisFinished(true);
                }else{
                    mFileInfo.setisFinished(false);
                }

                isFinished = true;//表示这个线程下载完成了




                checkThreadFinished(mCallback);

            } catch (Exception e) {
                e.printStackTrace();
                Log.d(TAG, "downloaderror: "+e.toString());
                mDeliver.obtainMessage(FILE_ERROR,e.toString()).sendToTarget();
                //异常的时候，也把数据库保存起来
                mDbThreadListener.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(),
                        mThreadInfo.getFinished());
                mCallback.failed(1,e.toString(),mFileInfo);

            }finally {
                if (bis != null) try {
                    bis.close();
                    if (raf != null) raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (conn != null) conn.disconnect();
            }

        }
    }
}
